package com.lcc.lynx.jdbc.util;

import com.lcc.lynx.common.exception.e.JDBCException;
import com.lcc.lynx.common.utils.LambdaUtils;
import com.lcc.lynx.common.utils.ReflectUtil;
import com.lcc.lynx.common.utils.SSupplier;
import com.lcc.lynx.common.utils.StrUtil;
import com.lcc.lynx.jdbc.IByIdService;
import com.lcc.lynx.jdbc.annotation.FieldLabel;
import com.lcc.lynx.jdbc.annotation.InsertRequired;
import com.lcc.lynx.jdbc.annotation.TableId;
import com.lcc.lynx.jdbc.pojo.TablePojo;
import com.lcc.lynx.jdbc.qw.TableDef;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.Map;
import java.util.stream.Collectors;

public class JDBCReflectUtil {

    /**
     * 获取主键字段值
     *
     * @param obj
     * @return
     */
    public static Field getTableIdField(Object obj) {
        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
            // 获取主键字段带 @TableId 注解的
            for (Field field : superClass.getDeclaredFields()) {
                if (field.isAnnotationPresent(TableId.class)) {
                    return field;
                }
            }
        }
        throw new JDBCException("未获取到主键字段，请使用@TableId注解标注主键字段");
    }


    public static <DV extends TablePojo> DV getDVAndSetId(Class<? extends IByIdService> aClass, Object id) {
        ParameterizedType type = (ParameterizedType) ((Class<?>) aClass.getGenericInterfaces()[0]).getGenericInterfaces()[0];
        // 实例化第一个泛型参数
        DV dv = ReflectUtil.invokeGenericIntf(type, 0);
        Field tableIdField = getTableIdField(dv);
        // 判断字段类型
        if (tableIdField.getType() == String.class) {
            ReflectUtil.setFieldValue(dv, tableIdField, id.toString());
        } else if (Number.class.isAssignableFrom(tableIdField.getType()) && id instanceof String) {
            try {
                ReflectUtil.setFieldValue(dv, tableIdField, tableIdField.getType().getConstructor(String.class).newInstance(id));
            } catch (Exception e) {
                throw new JDBCException("id转换成数字异常(" + e.getMessage() + "), id=" + id);
            }
        } else if (id instanceof Number) {
            ReflectUtil.setFieldValue(dv, tableIdField, id);
        } else {
            throw new JDBCException("id类型错误, 应为String或Number");
        }
        return dv;
    }

    /**
     * 判断对象的所有字段是否都为null为空, 集合是否为空
     *
     * @param dv
     * @param <DV>
     * @return
     * @author lcc
     * @date 2025/6/23 10:13
     */
    public static <DV extends TablePojo> boolean ifAllEmpty(DV dv) {
        if (dv == null) return true;
        for (Field field : ReflectUtil.getFields(dv.getClass()))
            if (StrUtil.isNotEmpty(ReflectUtil.getFieldValue(dv, field))) return false;
        return true;
    }

    /**
     * 判处插入必填字段是否为空
     *
     * @param dv
     * @param <DV>
     * @author lcc
     * @date 2025/6/27 10:52
     */
    public static <DV extends TablePojo> void checkInsertRequired(DV dv) {
        if (dv == null) throw new JDBCException("插入数据对象不能为空");
        String msg = ReflectUtil.getFields(dv.getClass()).stream()
                .filter(field -> field.isAnnotationPresent(InsertRequired.class)
                        && StrUtil.isEmpty(ReflectUtil.getFieldValue(dv, field)))
                .map(field -> field.getName())
                .collect(Collectors.joining(", "));
        if (StrUtil.isNotEmpty(msg)) {
            throw new JDBCException("插入必填字段不能为空：" + msg);
        }
    }

    /**
     * 获取字段标签
     *
     * @param sf
     * @param obj
     * @return
     */
    public static String getFieldLabel(SSupplier sf, Object obj) {
        String getName = LambdaUtils.resolve(sf);
        if (getName.startsWith("get") && getName.length() > 3) {
            char firstChar = Character.toLowerCase(getName.charAt(3));
            String name = firstChar + getName.substring(4);
            Field field = ReflectUtil.getField(obj.getClass(), name);
            if (field.isAnnotationPresent(FieldLabel.class)) {
                String value = field.getAnnotation(FieldLabel.class).value();
                return StrUtil.isNotEmpty(value) ? value : name;
            }
            return name;
        }
        throw new JDBCException("传入的是不get方法：" + getName);
    }


    /**
     * map转对象
     * @param map
     * @param clazz
     * @return
     * @param <R>
     * @author lcc
     * @date 2025/7/24 10:58
     */
    public static <R> R mapToObj(Map<String, Object> map, Class<R> clazz) {
        if(map == null || map.isEmpty()){
            return ReflectUtil.newInstance(clazz);
        }
        if(clazz == String.class){
            Object next = map.values().iterator().next();
            if(next == null){
                return null;
            }
            return (R) map.values().iterator().next().toString();
        }
        if(Number.class.isAssignableFrom(clazz)){
            Object next = map.values().iterator().next();
            if(next == null){
                return null;
            }
            if(next.getClass() == clazz){
                return (R) next;
            }
            return (R) ReflectUtil.convertValType(next, clazz);
        }

        R obj = ReflectUtil.newInstance(clazz);

        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value == null){
                continue;
            }
            String fieldName = JDBCUtil.toHump(key);
            Field field = ReflectUtil.getFieldLike(clazz, fieldName, key);
            if (field == null){
                continue;
            }

            ReflectUtil.setObjValue(obj, field, value);
        }
        return obj;
    }

    public static TableDef getTableDef(Class<? extends TableDef> tableDefClass) {
        return (TableDef) ReflectUtil.getStaticValue(tableDefClass, "_this_");
    }
}
